package it.uniroma2.art.coda.projectionrule;

import it.uniroma2.art.coda.structures.depends.DependencyObject;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Andrea Turbati
 */

public class ProjectionRule {

	private String uimaType;
	private String id; // this can be null
	private boolean nullId; // this says if the id has a meaningful value
	private double confidenceValue; // TODO choose a better name
	private Map<String, PlaceholderStruct> placeholdersMap; // this map contains the placeholders coming from
	// the nodes and the alias part of the projection rule
	private Collection<GraphStruct> graphList;
	private Collection<String> varList;
	private Collection<GraphStruct> whereList;
	private Map<String, String> parametersMap;

	// used only for internal reason, should not be used by developers
	private Map<String, Collection<DependencyObject>> tempDependsOnMap;

	// list of all the projection rule this one depends on
	private Collection<String> dependsPrList;

	// map containing the Projection Rules to which this Projection Rule depends on. The Projection Rule is
	// inside the DependsObject with other information
	private Map<String, Collection<DependencyObject>> dependsOnMap;

	// list of all the dependsOn of this projectionRule
	private List<DependencyObject> dependsOnList;

	// map containing the Projection Rules that depends on this Projection Rule
	private Map<String, Collection<ProjectionRule>> referredByMap;

	// private Map<String, Collection<FeatAndProperty> > featAndPropMap;

	// Add same structure to store information about the possible mapping between some feature on some
	// property.
	// The important thing is that the subject of this property MUST be some information inside the same
	// projection rule

	public ProjectionRule(String uimaTypeSystem, double confidenceValue) {
		initialize(uimaTypeSystem, confidenceValue, "not present");
		this.nullId = true;
	}

	public ProjectionRule(String uimaTypeSystem, double confidenceValue, String id) {
		initialize(uimaTypeSystem, confidenceValue, id);
		nullId = false;
	}

	private void initialize(String uimaTypeSystem, double confidenceValue, String id) {
		this.uimaType = uimaTypeSystem;
		this.confidenceValue = confidenceValue;
		parametersMap = new HashMap<String, String>();
		tempDependsOnMap = new HashMap<String, Collection<DependencyObject>>();
		dependsPrList = new ArrayList<String>();
		dependsOnMap = new HashMap<String, Collection<DependencyObject>>();
		dependsOnList = new ArrayList<DependencyObject>();
		referredByMap = new HashMap<String, Collection<ProjectionRule>>();
		placeholdersMap = new HashMap<String, PlaceholderStruct>();
		graphList = new ArrayList<GraphStruct>();
		whereList = new ArrayList<GraphStruct>();
		varList = new ArrayList<String>();
		this.id = id;
	}

	public boolean isIdNull() {
		return nullId;
	}

	public String getId() {
		if (nullId)
			return null;
		return id;
	}

	public String getUIMAType() {
		return uimaType;
	}

	public double getConfidenceValue() {
		return confidenceValue;
	}

	public boolean addPlaceholder(PlaceholderStruct placeholderStruct) {
		String placeholderName = placeholderStruct.getName();
		if (placeholdersMap.containsKey(placeholderName))
			return false;
		placeholdersMap.put(placeholderName, placeholderStruct);
		return true;
	}

	public Map<String, PlaceholderStruct> getPlaceholderMap() {
		return placeholdersMap;
	}

	public void addTripleToGraph(GraphStruct graph) {
		graphList.add(graph);
	}

	public Collection<GraphStruct> getGraphList() {
		return graphList;
	}

	public void addTripleToWhere(GraphStruct graph) {
		whereList.add(graph);
	}

	public Collection<GraphStruct> getWhereList() {
		return whereList;
	}

	public void addVar(String var) {
		varList.add(var);
	}

	public Collection<String> getVarList() {
		return varList;
	}

	public void addTempDependency(String typeOfDependecy, DependencyObject dependsObj) {
		if (dependsObj == null)
			return;
		if (tempDependsOnMap.containsKey(typeOfDependecy) == false)
			tempDependsOnMap.put(typeOfDependecy, new ArrayList<DependencyObject>());
		Collection<DependencyObject> prIdList = tempDependsOnMap.get(typeOfDependecy);
		prIdList.add(dependsObj);

		if (dependsPrList.contains(dependsObj.getRuleId()) == false)
			dependsPrList.add(dependsObj.getRuleId());
	}

	/*public Collection<String> getDependsPrList() {
		return dependsPrList;
	}*/

	public Map<String, Collection<DependencyObject>> getTempDependencyMap() {
		return tempDependsOnMap;
	}

	public void addDependency(String typeOfDependecy, DependencyObject dependsObj) {
		if (dependsOnMap.containsKey(typeOfDependecy) == false)
			dependsOnMap.put(typeOfDependecy, new ArrayList<DependencyObject>());
		Collection<DependencyObject> dependsObjList = dependsOnMap.get(typeOfDependecy);
		dependsObjList.add(dependsObj);
		dependsOnList.add(dependsObj);
	}

	public Map<String, Collection<DependencyObject>> getDependencyMap() {
		return dependsOnMap;
	}

	public Collection<DependencyObject> getDependencyList() {
		return dependsOnList;
	}

	public void addReferredBy(String typeOfReferrencing, ProjectionRule prRule) {
		if (referredByMap.containsKey(typeOfReferrencing) == false)
			referredByMap.put(typeOfReferrencing, new ArrayList<ProjectionRule>());
		Collection<ProjectionRule> prRuleList = referredByMap.get(typeOfReferrencing);
		prRuleList.add(prRule);
	}

	public Map<String, Collection<ProjectionRule>> getReferredByMap() {
		return referredByMap;
	}

	public boolean addParameter(String attName, String attValue) {
		if (parametersMap.containsKey(attValue))
			return false;
		parametersMap.put(attName, attValue);
		return true;
	}

	public Map<String, String> getParametersMap() {
		return parametersMap;
	}

}
